-
-
Notifications
You must be signed in to change notification settings - Fork 180
Add support for CLS variables with user-defined types #1024
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Signed-off-by: Klimenty Tsoutsman <[email protected]>
Signed-off-by: Klimenty Tsoutsman <[email protected]>
Signed-off-by: Klimenty Tsoutsman <[email protected]>
Signed-off-by: Klimenty Tsoutsman <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice! love the API and design decisions. I left a few comments, mostly questions and nitpicky shit.
Signed-off-by: Klimenty Tsoutsman <[email protected]>
Signed-off-by: Klimenty Tsoutsman <[email protected]>
Signed-off-by: Klimenty Tsoutsman <[email protected]>
Signed-off-by: Klimenty Tsoutsman <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thanks as always! Tested and working for me.
* The `cpu_local` macro now generates four functions for user-defined types:
```rust
pub fn replace(&self, value: #ty) -> #ty;
pub fn replace_guarded<G>(&self, mut value: #ty, guard: &G) -> #ty
where
G: CpuAtomicGuard
pub fn set(&self, value: #ty);
pub fn set_guarded<G>(&self, mut value: #ty, guard: &G)
where
G: CpuAtomicGuard
```
* The new `CpuAtomicGuard` trait is sealed, but implemented for
`preemption::PreemptionGuard` and `irq_safety::HeldInterrupts`.
Passing a reference to one of those guard types into either `set_guarded()`
or `replace_guarded()` can efficiently ensure that either preemption or
interrupts are disabled, meaning that the CPU-local variable can be
safely accessed in an atomic manner across multiple assembly instructions.
* However, this doesn't cover all use cases, so we also add two optional
arguments to the `cpu_local` macro:
1. `cls_dep`: a boolean that defaults to true, but can be set to false to
prevent the macro from generating functions that depend on `cls`.
This is only used by the `preemption` crate to avoid a circular dependency.
2. `stores_guard`: accepts a type denoting that the CLS variable stores an
`Option<impl cls::CpuAtomicGuard>`, such as the task switch preemption
guard. This argument modifies the signatures of `replace` and `set` to accept
the guard type by value, because the guard type obviates the need to pass in
a reference to another redundant guard (normally used to ensure atomicity).
Signed-off-by: Klimenty Tsoutsman <[email protected]> 8209f16
* The `cpu_local` macro now generates four functions for user-defined types:
```rust
pub fn replace(&self, value: #ty) -> #ty;
pub fn replace_guarded<G>(&self, mut value: #ty, guard: &G) -> #ty
where
G: CpuAtomicGuard
pub fn set(&self, value: #ty);
pub fn set_guarded<G>(&self, mut value: #ty, guard: &G)
where
G: CpuAtomicGuard
```
* The new `CpuAtomicGuard` trait is sealed, but implemented for
`preemption::PreemptionGuard` and `irq_safety::HeldInterrupts`.
Passing a reference to one of those guard types into either `set_guarded()`
or `replace_guarded()` can efficiently ensure that either preemption or
interrupts are disabled, meaning that the CPU-local variable can be
safely accessed in an atomic manner across multiple assembly instructions.
* However, this doesn't cover all use cases, so we also add two optional
arguments to the `cpu_local` macro:
1. `cls_dep`: a boolean that defaults to true, but can be set to false to
prevent the macro from generating functions that depend on `cls`.
This is only used by the `preemption` crate to avoid a circular dependency.
2. `stores_guard`: accepts a type denoting that the CLS variable stores an
`Option<impl cls::CpuAtomicGuard>`, such as the task switch preemption
guard. This argument modifies the signatures of `replace` and `set` to accept
the guard type by value, because the guard type obviates the need to pass in
a reference to another redundant guard (normally used to ensure atomicity).
Signed-off-by: Klimenty Tsoutsman <[email protected]> 8209f16
* The `cpu_local` macro now generates four functions for user-defined types:
```rust
pub fn replace(&self, value: #ty) -> #ty;
pub fn replace_guarded<G>(&self, mut value: #ty, guard: &G) -> #ty
where
G: CpuAtomicGuard
pub fn set(&self, value: #ty);
pub fn set_guarded<G>(&self, mut value: #ty, guard: &G)
where
G: CpuAtomicGuard
```
* The new `CpuAtomicGuard` trait is sealed, but implemented for
`preemption::PreemptionGuard` and `irq_safety::HeldInterrupts`.
Passing a reference to one of those guard types into either `set_guarded()`
or `replace_guarded()` can efficiently ensure that either preemption or
interrupts are disabled, meaning that the CPU-local variable can be
safely accessed in an atomic manner across multiple assembly instructions.
* However, this doesn't cover all use cases, so we also add two optional
arguments to the `cpu_local` macro:
1. `cls_dep`: a boolean that defaults to true, but can be set to false to
prevent the macro from generating functions that depend on `cls`.
This is only used by the `preemption` crate to avoid a circular dependency.
2. `stores_guard`: accepts a type denoting that the CLS variable stores an
`Option<impl cls::CpuAtomicGuard>`, such as the task switch preemption
guard. This argument modifies the signatures of `replace` and `set` to accept
the guard type by value, because the guard type obviates the need to pass in
a reference to another redundant guard (normally used to ensure atomicity).
Signed-off-by: Klimenty Tsoutsman <[email protected]>
The
cpu_localmacro now generates four functions for user-defined types:cls::Guardis implemented forpreemption::PreemptionGuardandirq_safety::HeldInterrupts. Passing a reference ensures that one or the other is disabled and so it is safe to access the CLS variable across multiple assembly instructions.However, this doesn't work for all use cases so the PR also adds two optional args to the
cpu_localmacro:cls_dep: Prevents generating functions that depend oncls. Used by thepreemptioncrate to avoid a circular dependency.stores_guard: Used for CLS variables that store anOption<impl cls::Guard>(i.e.TASK_SWITCH_PREEMPTION_GUARD). Modifies the signatures ofreplaceandset:Pain points
cpu_localwill generate a different API for integers, custom-types, andOption<impl cls::Guard>which can cause some confusion. In practice this shouldn't be a major problem becauseOption<impl cls::Guard>is a niche workaround used for a specific CLS variable, andcargo docworks as you'd expect, but still... Currently, the macro isn't actually necessary as we could recreate all of the functionality usingCpuLocalU*/CpuLocalCelltypes which would dramatically improve the unpredictable API. But (I'm pretty sure) the macro is necessary for when we implement dynamic CLS sections so there's no point removing it now.